/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit.handlers;

import static java.lang.Math.max;
import static java.lang.Math.min;

import java.util.LinkedList;
import java.util.List;

import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.uml2.uml.InteractionFragment;
import org.eclipse.uml2.uml.InteractionUse;
import org.eclipse.uml2.uml.Lifeline;

import com.cea.papyrus.core.utils.LookForElement;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.AnalyseCoveredCommand;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.AnalyseOwnerCommand;
import com.cea.papyrus.diagram.sequence.sedi.figures.SeDiSubpartFigure;
import com.cea.papyrus.diagram.sequence.sedi.model.command.CoverCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.SetConstraintCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.SetOwnerCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil;
import com.cea.papyrus.diagraminterchange2.di2.Diagram;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;

/**
 * Handles automatic layout of InteractionUses.
 * 
 * @author frankd@ifi.uio.no
 */
public class InteractionUseLayoutHandler implements LayoutHandler<InteractionUse> {
    @SuppressWarnings("unchecked")
    public Rectangle layout(Diagram diagram, InteractionUse iu) {
        // the left side should be slightly to the left of the leftmost
        // covered lifeline, and the right side slighly to the right of the
        // rightmost covered lifeline.
        // the top aside should be slightly below the lowest preceeding item
        // that cover any of the of covered lifelines, and correspondingly
        // for the bottom (slightly above)

        int left = Integer.MAX_VALUE; // , top = left;
        int right = Integer.MIN_VALUE; // , bottom = right;
        for (Lifeline lifeline : (List<Lifeline>) iu.getCovereds()) {
            GraphNode llview = ModelUtil.getGraphNode(lifeline, diagram);
            Rectangle bounds = new Rectangle(llview.getPosition(), llview.getSize());
            left = min(left, bounds.x);
            right = max(right, bounds.right());

            // TODO calculate top and bottom positions
            /*
             * int iuIndex = lifeline.getCoveredBys().indexOf(iu); if (iuIndex > 0) {
             * InteractionFragment fragment = (InteractionFragment)
             * lifeline.getCoveredBys().get(iuIndex - 1); if (fragment instanceof
             * EventOccurrence) { EventOccurrence eo = (EventOccurrence) fragment;
             * NamedElement owner = MessageUtil.getOwner(eo); diagram.getViewFor(owner)
             * eo.getReceiveMessage() } }
             */
        }

        return new Rectangle(left, 100, right - left, 50);
    }

    @SuppressWarnings("unchecked")
    public Command[] getMoveCommands(final EditPart fragmentPart, final Rectangle suggestedBounds) {

        final List<Command> cmds = new LinkedList<Command>();

        final GraphNode fragmentView = (GraphNode) fragmentPart.getModel();

        final SeDiSubpartFigure fragmentFigure =
                (SeDiSubpartFigure) ((GraphicalEditPart) fragmentPart).getFigure();

        final InteractionFragment fragment =
                ModelUtil.<InteractionFragment> getSemantic(fragmentView);

        // SetConstraintCommand
        // Move the lifeline
        // AnalyseCoveredByCommand
        // CoveredByCommand
        // Moving the fragment may have brought a different set of
        // lifelines beneath it.

        // covert bounds to absolute coords - required by AnalyseOwnerCmd
        Point locationAbs = suggestedBounds.getLocation();
        fragmentFigure.translateToAbsolute(locationAbs);

        final AnalyseOwnerCommand findOwnerCmd = new AnalyseOwnerCommand();
        findOwnerCmd.setDiagram(LookForElement.getDiagram(fragmentView));
        findOwnerCmd.setAnyEditPart(fragmentPart);
        findOwnerCmd.setLocation(locationAbs);

        final SetOwnerCommand setOwnerCmd = new SetOwnerCommand();
        setOwnerCmd.setFragment(fragment);
        // glue1: owner

        // Step 1
        final Rectangle preferredBounds = fragmentFigure.getPreferredBounds(suggestedBounds);
        final Command boundsCmd = new SetConstraintCommand(fragmentView, preferredBounds);

        // Step 2
        final AnalyseCoveredCommand analyseCoveredCmd = new AnalyseCoveredCommand();
        analyseCoveredCmd.setEditPart(fragmentPart);
        analyseCoveredCmd.setFragmentView(fragmentView);

        final CoverCommand coverCmd = new CoverCommand();
        coverCmd.setFragment(fragment);

        Command glue1 = new Command() {
            public void execute() {
                setOwnerCmd.setOwner(findOwnerCmd.getOwner());
            }
        };

        Command glue2 = new Command() {
            public void execute() {
                coverCmd.setCovered(analyseCoveredCmd.getCovered());
            }
        };

        cmds.add(findOwnerCmd);
        cmds.add(glue1);
        cmds.add(setOwnerCmd);
        cmds.add(boundsCmd);
        cmds.add(analyseCoveredCmd);
        cmds.add(glue2);
        cmds.add(coverCmd);

        return cmds.toArray(new Command[cmds.size()]);
    }
}
